/*
 * Copyright  2017-2019 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_common.h"
#include "fsl_elcdif.h"
#include "fsl_debug_console.h"

#include "fsl_gpio.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
#include "softspi.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
//extern  const unsigned char image___17213858537233[];
//extern  unsigned short _actest2[];

#define APP_ELCDIF LCDIF

#define APP_IMG_HEIGHT 800
#define APP_IMG_WIDTH  480
#define APP_HSW        20
#define APP_HFP        112
#define APP_HBP        100
#define APP_VSW        6
#define APP_VFP        20
#define APP_VBP        14
#define APP_POL_FLAGS \
    (kELCDIF_DataEnableActiveHigh | kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_DriveDataOnRisingClkEdge)

#define APP_LCD_RESET_PORT GPIO1
#define APP_LCD_RESET_PIN  16
    
/* Display. */
#define LCD_DISP_GPIO     GPIO1
#define LCD_DISP_GPIO_PIN 2
/* Back light. */
#define LCD_BL_GPIO     GPIO2
#define LCD_BL_GPIO_PIN 31

/* Frame buffer data alignment, for better performance, the LCDIF frame buffer should be 64B align. */
#define FRAME_BUFFER_ALIGN 64

#ifndef APP_LCDIF_DATA_BUS
#define APP_LCDIF_DATA_BUS kELCDIF_DataBus24Bit
#endif

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void BOARD_EnableLcdInterrupt(void);

/*******************************************************************************
 * Variables
 ******************************************************************************/

AT_NONCACHEABLE_SECTION_ALIGN(uint16_t s_frameBuffer_front[800*480], FRAME_BUFFER_ALIGN);
AT_NONCACHEABLE_SECTION_ALIGN(uint16_t s_frameBuffer_back[800*480], FRAME_BUFFER_ALIGN);
AT_NONCACHEABLE_SECTION_ALIGN(uint16_t s_frameBuffer_three[800*480], FRAME_BUFFER_ALIGN);

/*******************************************************************************
 * Code
 ******************************************************************************/
extern void APP_LCDIF_IRQHandler(void);

void LCDIF_IRQHandler(void)
{
    APP_LCDIF_IRQHandler();
    __DSB();
}

/* Enable interrupt. */
void BOARD_EnableLcdInterrupt(void)
{
    EnableIRQ(LCDIF_IRQn);
}

/* Initialize the LCD_DISP. */
void BOARD_InitLcd(void)
{
    gpio_pin_config_t config = {
        kGPIO_DigitalOutput,
        0,
        kGPIO_NoIntmode,
    };

    /* Backlight. */
    config.outputLogic = 1;
    GPIO_PinInit(LCD_BL_GPIO, LCD_BL_GPIO_PIN, &config);
}

void BOARD_InitLcdifPixelClock(void)
{
    /*
     * The desired output frame rate is 60Hz. So the pixel clock frequency is:
     * (480 + 41 + 4 + 18) * (272 + 10 + 4 + 2) * 60 = 9.2M.
     * Here set the LCDIF pixel clock to 9.3M.
     */

    /*
     * Initialize the Video PLL.
     * Video PLL output clock is OSC24M * (loopDivider + (denominator / numerator)) / postDivider = 93MHz.
     */
    clock_video_pll_config_t config = {
        .loopDivider = 60,
        .postDivider = 4,
        .numerator   = 0,
        .denominator = 0,
    };

    CLOCK_InitVideoPll(&config);

    /*
     * 000 derive clock from PLL2
     * 001 derive clock from PLL3 PFD3
     * 010 derive clock from PLL5
     * 011 derive clock from PLL2 PFD0
     * 100 derive clock from PLL2 PFD1
     * 101 derive clock from PLL3 PFD1
     */
    CLOCK_SetMux(kCLOCK_LcdifPreMux, 2);

    CLOCK_SetDiv(kCLOCK_LcdifPreDiv, 4);

    CLOCK_SetDiv(kCLOCK_LcdifDiv, 1);
}


void APP_ELCDIF_Init(void)
{
    const elcdif_rgb_mode_config_t config = {
        .panelWidth    = APP_IMG_WIDTH,
        .panelHeight   = APP_IMG_HEIGHT,
        .hsw           = APP_HSW,
        .hfp           = APP_HFP,
        .hbp           = APP_HBP,
        .vsw           = APP_VSW,
        .vfp           = APP_VFP,
        .vbp           = APP_VBP,
        .polarityFlags = APP_POL_FLAGS,
        .bufferAddr    = (uint32_t)&s_frameBuffer_front[0],
        .pixelFormat   = kELCDIF_PixelFormatRGB565,
        .dataBus       = APP_LCDIF_DATA_BUS,
    };

#if (defined(APP_ELCDIF_HAS_DISPLAY_INTERFACE) && APP_ELCDIF_HAS_DISPLAY_INTERFACE)
    BOARD_InitDisplayInterface();
#endif
    ELCDIF_RgbModeInit(APP_ELCDIF, &config);
}

/*!
 * @brief Main function
 */

void SetDisplayMemory(uint16_t* displayMemory,uint32_t size,uint16_t color)
{
	for(uint32_t i = 0;i<size;i++)
	{
		displayMemory[i] = color;
	}
}

void SetDisPlayBuff(uint8_t* buff,uint32_t heigh,uint32_t lengh)
{
    for(uint32_t i = 0;i<heigh;i++)
    {
        memcpy(&s_frameBuffer_front[0],&buff[(i*lengh*2)],lengh*2);
    }
}
#define USING_TEST 0
#if USING_TEST
extern unsigned short _acexcel[];
extern unsigned short _actest[];
extern void size_of_piture(void);
extern void size_of_test_piture(void);
#endif
void TM043YVHG35_Init(void)
{
    uint32_t index = 0;
    uint16_t color = 0x0000;
    uint32_t frameBufferIndex = 0;
    BOARD_InitLcdifPixelClock();
    BOARD_InitLcd();

    APP_ELCDIF_Init();
    MySPI_Init();
    
    LCD_Init();
    
    BOARD_EnableLcdInterrupt();
#if USING_TEST
    /* Clear the frame buffer. */
    for(uint32_t i = 0;i<266;i++)
    {
        color = (uint16_t)(i/(266/0x1f));
        if(color>0x001f)
        {
            color = 0x001f;
        }
        PRINTF("line = %d,i = %d,0x%x\r\n",i,i,color);
        SetDisplayMemory((uint16_t*)&s_frameBuffer[0][i*480],480,color);
    }
    for(uint32_t i = 0;i<265;i++)
    {
        color = (uint16_t)((i/(266/0x3f))*0x0020);
        if(color > 0x07D0)
        {
            color = 0x07D0;
        }
        PRINTF("line = %d,i = %d,0x%x\r\n",266+i,i,color);
        SetDisplayMemory((uint16_t*)&s_frameBuffer[0][266*480+i*480],480,color);
    }
    for(uint32_t i = 0;i<267;i++)
    {
        color = (uint32_t)((i/9)*0x0800);
        PRINTF("i = %d,i/8 = %d,0x%x\r\n",i,(i/8),color);
        SetDisplayMemory((uint16_t*)&s_frameBuffer[0][532*480+i*480],480,color);
    }
    
    //for(uint32_t i = 0;i<480*800;i++)
    //{
    //    s_frameBuffer[1][i] = _acexcel[i];
    //}
    for(uint16_t i = 0;i<16;i++)
    {
        SetDisplayMemory((uint16_t*)&s_frameBuffer[1][(i*50)*480],480*50,0x0001<<i);
    }
    SetDisplayMemory((uint16_t*)&s_frameBuffer[0],480*800,0x0000);
    //s_frameBuffer[1][i] = _acexcel[i];
    //size_of_test_piture();
    //size_of_piture();
#endif
    ELCDIF_EnableInterrupts(APP_ELCDIF, kELCDIF_VsyncEdgeInterruptEnable);
    ELCDIF_RgbModeStart(APP_ELCDIF);
#if USING_TEST
    while (1)
    {
      
      s_frameDone = false;
      /* Wait for previous frame complete. */
      while (!s_frameDone)
      {
      }
      frameBufferIndex ^= 1U;
    
      SDK_DelayAtLeastUs(2000000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
      if(frameBufferIndex)
      {
          ELCDIF_SetNextBufferAddr(APP_ELCDIF, (uint32_t)&s_frameBuffer[0]);
      }else{
          ELCDIF_SetNextBufferAddr(APP_ELCDIF, (uint32_t)&s_frameBuffer[1]);  
      }
    }
#endif
}
